﻿using Microsoft.EntityFrameworkCore;
using RotovapPlatform.Domain.Business.Interfaces;
using RotovapPlatform.Domain.Business.Recipes.Entities;
using RotovapPlatform.Infrastructure.Common.Data;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace RotovapPlatform.Infrastructure.Business.Experiments
{
	/// <summary>
	/// 实验仓储实现
	/// </summary>
	public class ExperimentRepository : IExperimentRepository
	{
		private readonly ExperimentDbContext _context;

		public ExperimentRepository(ExperimentDbContext context)
		{
			_context = context;
			Debug.WriteLine("ExperimentRepository initialized");
		}

		public async Task<IEnumerable<Experiment>> GetAllAsync()
		{
			try
			{
				var experiments = await _context.Experiments
					.Include<Experiment, RecipeDefinition>(e => e.Recipe)
					.ToListAsync();
				Debug.WriteLine($"Retrieved {experiments.Count} experiments");
				return experiments;
			}
			catch (Exception ex)
			{
				Debug.WriteLine($"Error in GetAllAsync: {ex.Message}");
				throw;
			}
		}

		public async Task<Experiment> GetByIdAsync(Guid experimentId)
		{
			try
			{
				var experiment = await _context.Experiments
					.Include<Experiment, RecipeDefinition>(e => e.Recipe)
					.FirstOrDefaultAsync(e => e.ExperimentId == experimentId);

				if (experiment == null)
				{
					Debug.WriteLine($"Experiment with ID {experimentId} not found");
				}
				else
				{
					Debug.WriteLine($"Retrieved experiment with ID: {experimentId}");
				}

				return experiment;
			}
			catch (Exception ex)
			{
				Debug.WriteLine($"Error in GetByIdAsync: {ex.Message}");
				throw;
			}
		}

		public async Task AddAsync(Experiment experiment)
		{
			try
			{
				// 重要：在添加实验前，确保断开与 Recipe 的关联，防止 EF Core 尝试插入已存在的配方
				var recipeId = experiment.RecipeId;
				var recipe = experiment.Recipe;
				experiment.Recipe = null;

				// 清除上下文中的所有跟踪实体，确保没有残留的跟踪状态
				_context.ChangeTracker.Clear();

				await _context.Experiments.AddAsync(experiment);
				await _context.SaveChangesAsync();

				// 保存完成后，恢复 Recipe 引用，但不触发数据库操作
				experiment.Recipe = recipe;
				experiment.RecipeId = recipeId;

				Debug.WriteLine($"Added Experiment with ID: {experiment.ExperimentId}");
			}
			catch (Exception ex)
			{
				Debug.WriteLine($"Error in AddAsync: {ex.Message}");
				throw;
			}
		}

		public async Task UpdateAsync(Experiment experiment)
		{
			try
			{
				// 重要：在更新实验前，确保断开与 Recipe 的关联，防止 EF Core 尝试更新已存在的配方
				var recipeId = experiment.RecipeId;
				var recipe = experiment.Recipe;
				experiment.Recipe = null;

				// 先分离所有实体，确保没有残留的跟踪状态
				_context.ChangeTracker.Clear();

				_context.Experiments.Update(experiment);
				await _context.SaveChangesAsync();

				// 更新完成后，恢复 Recipe 引用，但不触发数据库操作
				experiment.Recipe = recipe;
				experiment.RecipeId = recipeId;

				Debug.WriteLine($"Updated Experiment with ID: {experiment.ExperimentId}");
			}
			catch (Exception ex)
			{
				Debug.WriteLine($"Error in UpdateAsync: {ex.Message}");
				throw;
			}
		}

		public async Task DeleteAsync(Guid experimentId)
		{
			try
			{
				var experiment = await _context.Experiments.FindAsync(experimentId);
				if (experiment != null)
				{
					_context.Experiments.Remove(experiment);
					await _context.SaveChangesAsync();
					Debug.WriteLine($"Deleted Experiment with ID: {experimentId}");
				}
				else
				{
					Debug.WriteLine($"Experiment with ID {experimentId} not found for deletion");
				}
			}
			catch (Exception ex)
			{
				Debug.WriteLine($"Error in DeleteAsync: {ex.Message}");
				throw;
			}
		}

		public async Task<IEnumerable<Experiment>> GetByGroupIdAsync(Guid groupId)
		{
			try
			{
				var experiments = await _context.Experiments
					.Include<Experiment, RecipeDefinition>(e => e.Recipe)
					.Where(e => e.ExperimentGroupId == groupId)
					.ToListAsync();

				Debug.WriteLine($"Retrieved {experiments.Count} experiments for group ID: {groupId}");
				return experiments;
			}
			catch (Exception ex)
			{
				Debug.WriteLine($"Error in GetByGroupIdAsync: {ex.Message}");
				throw;
			}
		}

		public async Task<IEnumerable<Experiment>> GetByRecipeIdAsync(Guid recipeId)
		{
			try
			{
				var experiments = await _context.Experiments
					.Include<Experiment, RecipeDefinition>(e => e.Recipe)
					.Where(e => e.Recipe.RecipeId == recipeId)
					.ToListAsync();

				Debug.WriteLine($"Retrieved {experiments.Count} experiments for recipe ID: {recipeId}");
				return experiments;
			}
			catch (Exception ex)
			{
				Debug.WriteLine($"Error in GetByRecipeIdAsync: {ex.Message}");
				throw;
			}
		}

		public async Task<IEnumerable<Experiment>> GetByStatusAsync(ExperimentStatus status)
		{
			try
			{
				var experiments = await _context.Experiments
					.Include<Experiment, RecipeDefinition>(e => e.Recipe)
					.Where(e => e.Status == status)
					.ToListAsync();

				Debug.WriteLine($"Retrieved {experiments.Count} experiments with status: {status}");
				return experiments;
			}
			catch (Exception ex)
			{
				Debug.WriteLine($"Error in GetByStatusAsync: {ex.Message}");
				throw;
			}
		}

		public async Task<IEnumerable<Experiment>> GetByTimeRangeAsync(DateTime startTime, DateTime endTime)
		{
			try
			{
				var experiments = await _context.Experiments
					.Include<Experiment, RecipeDefinition>(e => e.Recipe)
					.Where(e =>
						(e.ExecutionStartTime >= startTime && e.ExecutionStartTime <= endTime) ||
						(e.ExecutionEndTime >= startTime && e.ExecutionEndTime <= endTime))
					.ToListAsync();

				Debug.WriteLine($"Retrieved {experiments.Count} experiments in time range: {startTime} to {endTime}");
				return experiments;
			}
			catch (Exception ex)
			{
				Debug.WriteLine($"Error in GetByTimeRangeAsync: {ex.Message}");
				throw;
			}
		}
	}
}